using JigLibX.Collision;
using JigLibX.Physics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SolarWinds.Cameras;
using SolarWinds.Input;
using SolarWinds.Screens;
using SolarWinds.Sound;
using SolarWinds.Transitions;

namespace SolarWinds
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class SolarWindsGame : Game
    {
        private readonly ScreenManager mScreenManager;

        private static Settings sSettings;
        public static Settings Settings
        {
            get { return sSettings; }
        }

        private static bool sIsRunning;
        public static bool IsRunning
        {
            get { return sIsRunning; }
        }

        private static GraphicsDeviceManager sGraphicsDeviceManager;
        public static GraphicsDeviceManager GraphicsDeviceManager
        {
            get { return sGraphicsDeviceManager; }
        }

        private static PhysicsSystem sPhysicSystem;
        private static PhysicsSystem PhysicsSystem
        {
            get { return sPhysicSystem; }
        }

        public static Camera Camera { get; set; }

        public SolarWindsGame()
        {
            Content.RootDirectory = "Content";

            // load settings
            sSettings = Settings.Load("settings.xml");

            // Create GraphicsDeviceManager
            sGraphicsDeviceManager = new GraphicsDeviceManager(this);

            sGraphicsDeviceManager.SynchronizeWithVerticalRetrace = true;
            IsFixedTimeStep = true;

            sPhysicSystem = new PhysicsSystem();

            sGraphicsDeviceManager.SynchronizeWithVerticalRetrace = false;
            IsFixedTimeStep = false;
            
            //physicSystem.CollisionSystem = new CollisionSystemGrid(32, 32, 32, 30, 30, 30);
            sPhysicSystem.CollisionSystem = new CollisionSystemBrute();
            //sPhysicSystem.CollisionSystem = new CollisionSystemSAP(); // TODO configure SAP solver

            sPhysicSystem.EnableFreezing = true;
            sPhysicSystem.SolverType = PhysicsSystem.Solver.Normal;
            sPhysicSystem.CollisionSystem.UseSweepTests = false;

            sPhysicSystem.NumCollisionIterations = 8;
            sPhysicSystem.NumContactIterations = 8;
            sPhysicSystem.NumPenetrationRelaxtionTimesteps = 15;
            sPhysicSystem.Gravity = Vector3.Zero;
            
            // Attach handlers to device event
            sGraphicsDeviceManager.PreparingDeviceSettings += PreparingDeviceSettings;

            // Create GraphicsDeviceManager
            sGraphicsDeviceManager.PreferredBackBufferWidth = sSettings.ScreenWidth;
            sGraphicsDeviceManager.PreferredBackBufferHeight = sSettings.ScreenHeight;
            sGraphicsDeviceManager.IsFullScreen = sSettings.FullScreen;
            sGraphicsDeviceManager.SynchronizeWithVerticalRetrace = sSettings.VerticalSync;
            sGraphicsDeviceManager.ApplyChanges();

            IsMouseVisible = true;

            var inputManager = new InputManager(this);
            Components.Add(inputManager);

            var soundManager = new SoundManager(this);
            Components.Add(soundManager);

            mScreenManager = new ScreenManager(this);
            Components.Add(mScreenManager);
        }

        static void PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
        {
            PresentationParameters pp = e.GraphicsDeviceInformation.PresentationParameters;

            pp.BackBufferFormat = SurfaceFormat.Color;
            pp.SwapEffect = SwapEffect.Discard;
            pp.AutoDepthStencilFormat = DepthFormat.Depth24Stencil8;
            pp.EnableAutoDepthStencil = true;
            pp.PresentationInterval = PresentInterval.Immediate;
            pp.MultiSampleType = MultiSampleType.None;
            pp.RenderTargetUsage = RenderTargetUsage.PreserveContents;
        }

        protected override void Initialize()
        {
            Window.Title = sSettings.WindowTitle;

            base.Initialize();
        }

        protected override void BeginRun()
        {
            base.BeginRun();

            sIsRunning = true;

            // fire up the first screens 
            mScreenManager.PushScreen(new BackgroundScreen(this));
            mScreenManager.PushScreen(new MainMenuScreen(this), new SlideTransition(this));
        }

        protected override void EndRun()
        {
            sIsRunning = false;

            base.EndRun();
        }
    }
}